/**
 * @file   socket.cpp
 * @author Pedro
 * @date   Thu Nov  6 12:26:14 2008
 * 
 * @brief  Funciones de comunicación entre hosts para empezar y parar la grabación
 * 
 * 
 */
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>          /* hostent struct, gethostbyname() */
#include <arpa/inet.h>      /* inet_ntoa() to format IP address */

#include <pthread.h>

#include "socket.h"

extern bool grabar_flag;

void Die(const char *mess) 
{ 
    perror(mess); 
}

void * pthread_func_client_pthread(void * param);
int client(const char * ipaddress, int port, char *buffer, int sizebuffer);
void * pthread_func_server_pthread(void * param);





socket_params_t * init_master_socket(const char * ipaddress, int port)
{
    socket_params_t *socket_params = new socket_params_t;

    strncpy(socket_params->ipaddress, ipaddress, 20);
    socket_params->port = port;
    socket_params->quit = 0;
    socket_params->master_is_grab = 0;
    socket_params->master_is_active = 1;
    socket_params->hiloserver = 0;
    socket_params->hiloclient = 0;

    printf("Pthread_Create( Thread_Func_Client_Pthread ...);\n");
    pthread_create(&socket_params->hiloclient, NULL, 
		   pthread_func_client_pthread, (void *)socket_params);

    return socket_params;
}


socket_params_t * finish_master_socket(socket_params_t * socket_params)
{
    if (socket_params && socket_params->hiloclient)
    {
	socket_params->quit = true;
	pthread_cancel(socket_params->hiloclient);
	pthread_join(socket_params->hiloclient, NULL);
	printf("Fin Hilo Master\n");
	delete []socket_params;
	socket_params = 0;
    }
    return socket_params;
}


void * pthread_func_client_pthread(void * param)
{
    socket_params_t *socket_params = (socket_params_t *)param;
    char buffer[100];
    int old_grabar_flag = grabar_flag;

    while (!socket_params->quit)
    {
	if (grabar_flag != old_grabar_flag)
	{
	    sprintf(buffer, "%s\n", grabar_flag?"ON":"OFF");
	    client(socket_params->ipaddress, socket_params->port, buffer, strlen(buffer)+1);
	    old_grabar_flag = grabar_flag;
	}
	sleep(2); //2 minutos
    }
    
    return NULL;
}

int client(const char * ipaddress, int port, char *buffer, int sizebuffer)
{
    int sock;
    struct sockaddr_in echoserver;
    int echolen;

    /* Create the TCP socket */
    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
	Die("Failed to create socket");
    }



    /* Construct the server sockaddr_in structure */
    memset(&echoserver, 0, sizeof(echoserver));       /* Clear struct */
    echoserver.sin_family = AF_INET;                  /* Internet/IP */
    echoserver.sin_addr.s_addr = inet_addr(ipaddress);  /* IP address */
    echoserver.sin_port = htons(port);       /* server port */
    /* Establish connection */
    if (connect(sock,
		(struct sockaddr *) &echoserver,
		sizeof(echoserver)) < 0) {
	//Die("Failed to connect with server");
	return 0;
    }
           
      
    /* Send the word to the server */
    echolen = strlen(buffer);
    if (send(sock, buffer, echolen, 0) != echolen) {
	Die("Mismatch in number of sent bytes");
	return 0;
    }
    close(sock);
    return strlen(buffer);
}
          

/************************************************

SERVER

************************************************/


#define MAXPENDING 5    /* Max connection requests */
#define BUFFSIZE 32


int HandleClient(int sock, socket_params_t * socket_params ) {
    char buffer[BUFFSIZE];
    int seguir;

    /* Receive message */
    if (recv(sock, buffer, BUFFSIZE, 0) < 0) {
	Die("Failed to receive initial bytes from client");
    }
    if (strncmp(buffer, "ON", 2) == 0)
	socket_params->master_is_grab = 1;
    else if (strncmp(buffer, "OFF", 3) == 0)
	socket_params->master_is_grab = 0;
    else if (strncmp(buffer, "POWEROFF", 8) == 0)
	socket_params->master_is_active = 0;

    seguir = socket_params->callback(socket_params, socket_params->callback_params);
    close(sock);
    return seguir;
}

            
socket_params_t * init_slave_socket(int port) 
{
    socket_params_t *p = new socket_params_t;

    p->port = port;
    p->master_is_grab = 0;
    p->master_is_active = 1;
    p->hiloserver = 0;
    p->hiloclient = 0;

    printf("Thread_Create( Thread_Func_Server_Pthread ...);\n");
    pthread_create(&p->hiloserver, NULL, pthread_func_server_pthread, (void*)p);

    return p;
}

socket_params_t * finish_slave_socket(socket_params_t * socket_params)
{
    if (socket_params && socket_params->hiloserver )
    {
	socket_params->quit = true;
	pthread_cancel(socket_params->hiloserver);
	pthread_join(socket_params->hiloserver, NULL);
	printf("Fin Hilo Slave\n");
	socket_params = 0;
    }
    return socket_params;
}


void * pthread_func_server_pthread(void * param)
{
    socket_params_t * socket_params = (socket_params_t *)param;
    int serversock, clientsock;
    struct sockaddr_in echoserver, echoclient;
  

    /* Create the TCP socket */
    if ((serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
	Die("Failed to create socket");
    }
    /* Construct the server sockaddr_in structure */
    memset(&echoserver, 0, sizeof(echoserver));       /* Clear struct */
    echoserver.sin_family = AF_INET;                  /* Internet/IP */
    echoserver.sin_addr.s_addr = htonl(INADDR_ANY);   /* Incoming addr */
    echoserver.sin_port = htons(socket_params->port);       /* server port */
           


    /* Bind the server socket */
    if (bind(serversock, (struct sockaddr *) &echoserver,
	     sizeof(echoserver)) < 0) {
	Die("Failed to bind the server socket");
    }
    /* Listen on the server socket */
    if (listen(serversock, MAXPENDING) < 0) {
	Die("Failed to listen on server socket");
    }

    int seguir=1;
    while (seguir) 
    {
	unsigned int clientlen = sizeof(echoclient);
	/* Wait for client connection */
	if ((clientsock =
	     accept(serversock, (struct sockaddr *) &echoclient,
		    &clientlen)) < 0) {
	    Die("Failed to accept client connection");
	}
	//fprintf(stdout, "Client connected: %s\n", inet_ntoa(echoclient.sin_addr));
	seguir = HandleClient(clientsock, socket_params);
    }

    return NULL;
}
           

